/* jshint esversion: 6 */
console.log('%c PetUI %c PetUI2.0框架\n %c作者: 小瑞猫',
  'font-family: "Helvetica Neue",Helvetica, Arial, sans-serif;font-size:64px;color:#FFB6C1;-webkit-text-fill-color:#FFB6C1;-webkit-text-stroke: 1px #FFB6C1;',
  'font-size:25px;color:#FFB6C1;', 'font-size:15px;color:#FFB6C1;');
/****************************错误日志****************************/
// 日志模块
var PetLog = {
  // 日志
  Log: function (data) {

  },
  // 错误
  Error: function (data) {
    // 命令行输出提示
    console.log('%c[PetLog] 提交错误至后台', 'font-size:15px;color:#FFB6C1;');
    // 处理错误
    var text = "";
    if (typeof data == "string") {
      text = data;
    } else {
      for (var key in data) {
        text += key + " : " + data[key] + "\n";
      }
    }
    // 提示
    if (PetUI.Prompt) {
      var err = PetUI.Prompt(text, 10000);
      err.CSS("text-align: left");
      err.classList = "Red";
    } else {
      alert(text);
    }
    // 上传 BUG
    PetUI.HTTP.Get({
      url: "/ErrorToSubmit?Error=" + JSON.stringify(data)
    });
  },
};
// 继承错误
/*
window.onerror = function (msg, url, line, col, error) {
  var data = {};
  //不一定所有浏览器都支持col参数
  col = col || (window.event && window.event.errorCharacter) || 0;
  data.url = url;
  data.line = line;
  data.col = col;
  if (!!error && !!error.stack) {
    //如果浏览器有堆栈信息
    //直接使用
    data.msg = error.stack.toString();
  } else if (!!arguments.callee) {
    //尝试通过callee拿堆栈信息
    var ext = [];
    var f = arguments.callee.caller,
      c = 3;
    //这里只拿三层堆栈信息
    while (f && (--c > 0)) {
      ext.push(f.toString());
      if (f === f.caller) {
        break; //如果有环
      }
      f = f.caller;
    }
    ext = ext.join(",");
    if (error != null) {
      data.msg = error.stack.toString();
    }
  }
  // 传递到错误处理
  PetLog.Error(data);
  return true;
};
*/
// 创建UI框架
(function () {
  /******************************UI****************************/
  var PetUI = function (...e) {
    if (typeof e[0] != "undefined") {
      switch (e[0][0]) {
        case "#":
          return document.getElementById(e[0].slice(1)); // ID 查找
        case ".":
          return document.getElementById(e[0].slice(1)); // ID 查找
        default:
          if (e.length == 0) {
            return;
          }
          // 默认返回创建 对  PetUI.Create 封装
          if (e.length <= 2) {
            return PetUI.Create(e[0], e[1]);
          }
      }
    }
  };
  /****************************UI功能库****************************/
  Reflect.setPrototypeOf(PetUI, {
    // HTTP 通信
    //* 调用方式
    //*	option	 -> 参数对象 { url , method , data , timeout , responseType }
    //*	callback -> function(err,result)
    HTTP: {
      quest: function (option, callback) {
        var url = option.url;
        var method = option.method;
        var data = option.data;
        var timeout = option.timeout || 0;
        var xhr = null;
        try {
          xhr = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
          try {
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
          } catch (e1) {
            xhr = new XMLHttpRequest();
          }
        }
        // 返回数据类型
        xhr.responseType = (([
          'text',
          'arraybuffer',
          'blob',
          'document'
        ]).indexOf(option.responseType) != -1) ? option.responseType : 'text';
        if (timeout > 0) {
          xhr.timeout = timeout;
        }
        // 设置回调函数
        xhr.onreadystatechange = () => {
          if (xhr.readyState == 4) {
            if (xhr.status >= 200 && xhr.status < 400) {
              var result = '';
              switch (xhr.responseType) {
                case 'text':
                  try {
                    result = JSON.parse(xhr.responseText);
                  } catch (e) {
                    result = xhr.responseText;
                  }
                  break;
                case 'document':
                  result = xhr.responseXML;
                  break;
                default:
                  result = xhr.response;
              }
              if (callback) {
                callback(null, result);
              }
            } else {
              if (callback) {
                callback('status: ' + xhr.status);
              }
            }
          }
        };
        // 打开连接
        xhr.open(method, url, true);
        if (typeof data === 'object') {
          try {
            data = JSON.stringify(data);
          } catch (e) {}
        }
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;");
        // 发送数据
        xhr.send(data);
        xhr.ontimeout = function () {
          if (callback) {
            callback('timeout');
          }
          console.log('%c连%c接%c超%c时', 'color:red', 'color:orange', 'color:purple', 'color:green');
        };
      },
      // get 与 post 通信
      Get: function (url, callback) {
        var option = url.url ? url : {
          url: url
        };
        option.responseType = (([
          'text',
          'arraybuffer',
          'blob',
          'document'
        ]).indexOf(url.responseType ? url.responseType : "") != -1) ? url.responseType : 'text';
        option.method = 'get';
        this.quest(option, callback);
      },
      Post: function (option, callback) {
        option.method = 'post';
        this.quest(option, callback);
      }
    },
    // 获得网页窗口坐标信息
    Position: (function () {
      var $ = {};
      $.ResizeAffair = undefined; // 大小调整
      $.ResizeScroll = undefined; // 滚动条滚动
      $.Scroll = {
        X: 0,
        Y: 0
      };
      $.Win = {
        Width: 0,
        Height: 0
      };
      // 坐标偏移/限制
      $.WinSkewing = {
        top: 0,
        left: 0,
        Width: 0,
        Height: 0
      };
      // 修改大小
      $.Uinc = function () {
        // 滚动条位置
        if (self.pageYOffset) {
          $.Scroll.Y = self.pageYOffset;
          $.Scroll.X = self.pageXOffset;
        } else if (document.documentElement && document.documentElement.scrollTop) {
          $.Scroll.Y = document.documentElement.scrollTop;
          $.Scroll.X = document.documentElement.scrollLeft;
        } else if (document.body) {
          $.Scroll.Y = document.body.scrollTop;
          $.Scroll.X = document.body.scrollLeft;
        }
        // 获取窗口宽度
        if (window.innerWidth)
          $.Win.Width = window.innerWidth;
        else if ((document.body) && (document.body.clientWidth)) {
          $.Win.Width = document.body.clientWidth;
        }
        // 获取窗口高度
        if (window.innerHeight)
          $.Win.Height = window.innerHeight;
        else if ((document.body) && (document.body.clientHeight)) {
          $.Win.Height = document.body.clientHeight;
        }
        // 通过深入 Document 内部对 body 进行检测，获取窗口大小
        if (document.documentElement && document.documentElement.clientHeight && document.documentElement.clientWidth) {
          $.Win.Height = document.documentElement.clientHeight;
          $.Win.Width = document.documentElement.clientWidth;
        }
        $.Win.Height = $.Win.Height + $.WinSkewing.Height;
        $.Win.Width = $.Win.Width + $.WinSkewing.Width;
      };
      // 设定更变条件
      window.addEventListener("scroll", function () {
        $.Uinc();
        if (typeof $.ResizeScroll == "function") {
          $.ResizeScroll();
        }
      });
      window.addEventListener("resize", function () {
        $.Uinc();
        if (typeof $.ResizeAffair == "function") {
          $.ResizeAffair();
        }
      });
      $.Uinc();
      return $;
    })(),
    // 打字效果
    Typing: function () {
      var Ty = Object(function (str, obj, callback, T) {
        var t = T ? T : 100;
        if (Ty.I <= str.length) {
          obj.innerText = str.slice(0, Ty.I++);
          var timer = window.setTimeout(function () {
            Ty(str, obj, callback, t);
            window.clearTimeout(timer);
          }, t); //递归调用
        } else {
          Ty.I = 0;
          if (callback == null) {
            return;
          }
          if (typeof (callback) !== "undefined") {
            callback();
          }
        }
      });
      Ty.I = 0;
      return Ty;
    },
    // 获得 文本/字节集 的 Src 
    SrcFile: function (data) {
      this.aFilePath = [];
      this.aFilePath.push(data);
      this.blob = new Blob(this.aFilePath, {
        type: 'application/octet-binary'
      });
      this.src = window.URL.createObjectURL(this.blob);
    },
    // 动态加载 File
    GetFile: function (url, callback) {
      this.HTTP.Get({
        url: url,
        responseType: 'blob'
      }, (e, data) => {
        if (e == null) {
          if (callback) {
            if (this.ToString(data) == "Blob") {
              var reader = new FileReader();
              reader.onload = function (event) {
                callback(reader.result);
              };
              reader.readAsText(data);
            } else {
              callback(data);
            }
          }
        } else {
          console.warn(url, e);
        }
      });
    },
    // Blob 分割
    //    blob  目标
    //    start 开始位置
    //    end   结束位置  
    //    type  类型
    SliceBlob: function (blob, start, end, type) {
      type = type || blob.type;
      if (blob.mozSlice) {
        return blob.mozSlice(start, end, type);
      } else if (blob.webkitSlice) {
        return blob.webkitSlice(start, end, type);
      } else {
        throw new Error("This doesn't work!");
      }
    },
    // 单击转双击判定
    DoubleClick: function (Click, Double, Mousedown, Mouseup) {
      var mouseup = null;
      var $this = function (...e) {
        if (typeof (Mousedown) == "function") {
          Mousedown(...e);
        }
        if ($this.look) {
          $this.Dblclick = true;
          return;
        }
        $this.look = true;
        var timer = window.setTimeout(function () {
          if (!($this.look)) {
            return;
          }
          if ($this.Dblclick) {
            if (typeof (Double) == "function") {
              Double(...e);
            }
          } else {
            if (typeof (Click) == "function") {
              Click(...e);
            }
          }
          $this.look = false;
          $this.Dblclick = false;
          if (mouseup != null && typeof (Mouseup) == "function") {
            Mouseup(...mouseup);
            mouseup = null;
          }
          window.clearTimeout(timer);
        }, 250);
      };
      $this.Mouseup = (...e) => {
        if ($this.look && $this.Dblclick) {
          if (typeof (Mouseup) == "function") {
            Mouseup(...e);
          }
        } else {
          mouseup = e;
        }
      };
      $this.look = false;
      $this.Dblclick = false;
      return $this;
    },
    // 不规则矩形判定
    IsPointInPolygon: function (x, y, coords, width, height) {
      var wn = 0;
      width = width ? width : 1;
      height = height ? height : 1;
      for (var shiftP, shift = coords[1] * height > y, i = 3; i < coords.length; i += 2) {
        shiftP = shift;
        shift = coords[i] * height > y;
        if (shiftP != shift) {
          var n = (shiftP ? 1 : 0) - (shift ? 1 : 0);
          // dot product for vectors (c[0]-x, c[1]-y) . (c[2]-x, c[3]-y)
          if (n * ((coords[i - 3] * width - x) * (coords[i - 0] * height - y) - (coords[i - 2] * height - y) * (coords[i - 1] * width - x)) > 0) {
            wn += n;
          }
        }
      }
      return wn;
    },
    // Guid 标记获取
    Guid: function () {
      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
      });
    },
    // 平台判定 
    IsPC: function () {
      var userAgentInfo = navigator.userAgent;
      var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
      var flag = true;
      for (var v = 0; v < Agents.length; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
          flag = false;
          break;
        }
      }
      return flag;
    },
    // 是否支持触摸
    HasTouch: function () {
      var touchObj = {};
      touchObj.isSupportTouch = "ontouchend" in document ? true : false;
      touchObj.isEvent = touchObj.isSupportTouch ? true : false;
      return touchObj.isEvent;
    },
    // 对象添加事件触发功能
    SetChangeEvent: function (obj, event) {
      var $this = this;
      this.Proto = [];
      this.TheDefaultReturn = null;
      this.Transmit = false;
      this.Destroy = function (id) {
        for (var i in $this.Proto) {
          if ($this.Proto[i] == id) {
            $this.Proto.splice(i, 1);
            return true;
          }
        }
        return false;
      };
      // 保存原函数指针
      try {
        if (typeof obj[event] == "function") {
          this.Proto.push(obj[event]);
        }
        var ret = function (...name) {
          var Ret, i;
          if ($this.TheDefaultReturn != undefined) {
            Ret = $this.Proto[$this.TheDefaultReturn].call(this, ...name);
            return Ret;
          }
          try {
            for (i in $this.Proto) {
              $this.Proto[i].call(this, ...name);
              // 传递返回
              if ($this.Transmit) {
                $this.Transmit = false;
                return;
              }
            }
          } catch (err) {
            console.warn(err, "\nID: " + i);
            $this.Proto.splice(i, 1);
          }
        };
        Object.defineProperty(obj, event, {
          // 改变事件 添加到事件触发数组
          set: function (name) {
            if (name != undefined) {
              obj[event + "ID"] = $this.Proto.length;
              $this.Proto.push(name);
            }
          },
          // 调用事件 循环调用事件
          get: function () {
            if ($this.Proto == 1) {
              return $this.Proto[0];
            }
            // 返回 构建数组
            return ret;
          }
        });
      } catch (err) {
        console.warn(err);
        return null;
      }
    },
    // 对象添加初始化
    SetOnload: function (Obj) {
      // 对象信息
      var $ = this;
      this.Proto = [];
      this.lock = false;
      // 保存之前需要初始化的函数
      if (typeof Obj.onload == "function") {
        this.Proto.push(Obj.onload);
      }
      // 初始化完成
      this.onload = function (...n) {
        $.Param = n;
        $.lock = true;
        for (var i in $.Proto) {
          $.Proto[i](...n);
        }
        $.Proto.splice(0, $.Proto.length);
      };
      // 设置初始化
      Obj.onload = $.onload;
      // 拦截其他初始化参数设置
      Object.defineProperty(Obj, 'onload', {
        // 改变事件 添加到事件触发数组
        set: function (name) {
          if (typeof name != "function") {
            return;
          }
          if ($.lock) {
            if ($.Param != undefined) {
              name(...$.Param);
            } else {
              name();
            }
          } else {
            $.Proto.push(name);
          }
        },
        get: function () {
          return $;
        }
      });
    },
    // 拷贝对象到目标
    //    origin 拷贝目标
    //    target 拷贝对象
    DeepClone: function (origin, target) {
      target = target || {};
      for (var prop in target) {
        if (target.hasOwnProperty(prop)) {
          if (target[prop] !== null && typeof target[prop] === 'object') {
            origin[prop] = Object.prototype.toString.call(target[prop]) === '[object Array]' ? [] : {};
            PetUI.DeepClone(origin[prop], target[prop]);
          } else {
            origin[prop] = target[prop];
          }
        }
      }
    },
    // 对象拦截
    //    obj   拦截对象
    //    name  拦截函数名
    //    call {Set: (n) => { },Get: (n) => {}} 对象
    ObjectIntercept: function (obj, name, call) {
      // 触发事件回调
      var Call = {
          Set: (n) => {
            return n;
          },
          Get: (n) => {
            return n;
          }
        },
        $ = this;
      if (call) {
        if (call.Set) {
          Call.Set = call.Set;
        }
        if (call.Get) {
          Call.Get = call.Get;
        }
      }
      // 设置事件
      var _name = "_" + name;
      obj[_name] = obj[name];
      // 拦截事件
      Object.defineProperty(obj, name, {
        set: function (n) {
          obj[_name] = Call.Set(n);
        },
        get: function () {
          return Call.Get(obj[_name]);
        }
      });
      return Call;
    },
    // GetClassName 查找 元素 class
    //  obj是要获取元素的父级
    //  sName是class名字
    GetClassName: function (obj, sName) {
      if (document.getElementsByClassName) {
        return obj.getElementsByClassName('sName');
      } else {
        var aTmp = obj.getElementsByTagName('*');
        var aRes = [];
        var arr = [];

        for (var i = 0; i < aTmp.length; i++) {
          arr = aTmp[i].className.split(' ');
          for (var j = 0; j < arr.length; j++) {
            if (arr[j] == sName) {
              aRes.push(aTmp[i]);
            }
          }
        }
        return aRes;
      }
    },
    // 得到Obj类型
    ToString: function (Obj) {
      let tosrt = (toString.call(Obj).split(" "))[1];
      return tosrt.substr(0, tosrt.length - 1);
    },
    // 得到URL参数
    GetRequest: function () {
      var url = decodeURI(location.search); //获取url中"?"符后的字串  
      var theRequest = {};
      if (url.indexOf("?") != -1) {
        var str = url.substr(1);
        strs = str.split("&");
        for (var i = 0; i < strs.length; i++) {
          theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
        }
      }
      return theRequest;
    }
  });
  /****************************附加功能****************************/
  // 注册事件
  PetUI.AddHandler = function (object, type, handler, options) {
    var E = function (e) {
      e = e || window.event;
      e.buttons = 1;
      if (e.changedTouches) {
        e.clientX = e.changedTouches[0].pageX;
        e.clientY = e.changedTouches[0].pageY;
      }
      return e;
    };
    if (object.addEventListener) {
      object.addEventListener(type, e => handler(E(e)), options);
    } else if (object.attachEvent) {
      object.attachEvent("on" + type, e => handler(E(e)), options);
    } else {
      object["on" + type] = e => handler(E(e));
    }
  };
  // 禁止菜单显示
  PetUI.BanMenu = function () {
    document.oncontextmenu = function (e) {
      return false;
    };
  };
  // 创建元素
  PetUI.Create = function (type, Param) {
    // 判断是否是添加
    if (typeof type != "string" && type != undefined) {
      if (this.appendChild == undefined) {
        return this;
      }
      return this.appendChild(type);
    }
    var create = document.createElement(type);
    // 判定自身是否是子元素
    if (this.toString() != "[object Object]" && this.toString() != "[object Function]") {
      this.appendChild(create);
    }
    // 继承处理
    PetUI.SetElement.call(this, create, Param);
    return create;
  };
  // 设置元素
  // * create 新元素
  // * Param  参数
  PetUI.SetElement = function (create, Param) {
    // 继承
    PetUI.DeepClone(create, PetUI.Additional);
    create.Create = PetUI.Create;
    // 设置参数
    for (var key in Param) {
      if (typeof create[key] != undefined) {
        if (typeof create[key] == "function") {
          create[key](Param[key]);
        } else {
          create[key] = Param[key];
        }
      }
    }
    // 设置缩放
    var Top = 0,
      Left = 0,
      lock = false;
    // 事件传递
    var Recovery = () => {
      create.style = create.style.cssText + 'top:' + parseInt(Top * (PetUI.Position.Win.Height + PetUI.Position.Scroll.Y)) + "px;left:" + parseInt(Left * (PetUI.Position.Win.Width + PetUI.Position.Scroll.X)) + "px;";
    };
    PetUI.ObjectIntercept(create.UI, "RelativeSize").Set = function (name) {
      if (name && lock == false) {
        // 元素位置修改
        var Save = (n) => {
          // 设置坐标
          create.style = create.style.cssText + 'top:' + create.style._top + ";left:" + create.style._left;
          // 设置相对坐标
          Top = create.offsetTop / (PetUI.Position.Win.Height + PetUI.Position.Scroll.Y);
          Left = create.offsetLeft / (PetUI.Position.Win.Width + PetUI.Position.Scroll.X);
          return n;
        };
        // 设置事件
        PetUI.Position.ResizeAffair = Recovery;
        lock = true;
        // 保证记录坐标
        PetUI.ObjectIntercept(create.style, "top").Set = Save;
        PetUI.ObjectIntercept(create.style, "left").Set = Save;
      }
      if (name == false && lock) {
        lock = false;
        PetUI.Position.AddResizeAffair.Destroy(Recovery);
      }
      return name;
    };
    return create;
  };
  // UI附加功能
  PetUI.Additional = {
    // style 设置函数
    CSS: function (style) {
      var typ = typeof style;
      if (typ == "object") {
        var css = "";
        if (this.style) {
          for (var x in style) {
            if (style[x] != undefined) {
              css += ";" + x + ":" + style[x];
            }
          }
        }
        if (css != "") {
          this.style.cssText += css;
        }
      } else if (typ == "string") {
        this.style = (this.cssText == undefined ? "" : this.cssText) + ";" + style;
      }
      return this;
    },
    // 删除元素函数
    Destroy: function () {
      // 处理元素删除
      (this.parentNode).removeChild(this);
    },
    // 创建到目标
    //  state 添加到第一个元素
    //   Obj 目标
    Child: function (state, Obj) {
      // 判断父节点类型
      var to = this.toString();
      Obj = Obj == undefined ? document.body : Obj;
      if (to != "[object Object]" || to != "[object Window]") {
        // 自身添加到 Obj
        if (state && Obj.childNodes[0] != undefined) {
          Obj.insertBefore(this, Obj.childNodes[0]);
        } else {
          Obj.appendChild(this);
        }
      }
      // 返回自身父节点
      return this;
    },
    // 添加元素
    //   obj    元素/元素名
    //   Param  元素参数
    //   state 添加到第一个元素
    Add: function (obj, Param, state) {
      // 是否为元素名
      if (typeof obj == "string") {
        obj = PetUI.Create(obj);
      }
      // 设置参数
      if (Param != undefined) {
        for (var key in Param) {
          if (typeof obj[key] != undefined) {
            if (typeof obj[key] == "function") {
              if (PetUI.ToString(Param[key]) == "Array") {
                obj[key](...Param[key]);
              } else {
                obj[key](Param[key]);
              }
            } else {
              obj[key] = Param[key];
            }
          }
        }
      }
      // 添加新元素
      if (state && this.childNodes[0] != undefined) {
        this.insertBefore(obj, this.childNodes[0]);
      } else {
        this.appendChild(obj);
      }
      // 返回自身父节点
      return this;
    },
    // 事件注册
    AddHandler: function (type, handler, options) {
      if (this.addEventListener) {
        this.addEventListener(type, handler, options);
      } else if (this.attachEvent) {
        this.attachEvent("on" + type, handler, options);
      } else {
        this["on" + type] = handler;
      }
    },
    // 样式
    Class: function (style, state) {
      if (typeof style == "string") {
        this.classList.toggle(style, state);
      } else {
        for (var i = 0; i < style.length; i++) {
          this.classList.toggle(style[i], state);
        }
      }
    },
    // 元素隐藏/显示
    Display: function (state) {
      if (state == undefined) {
        return this.style.display != 'none';
      }
      if (state) {
        this.style.display = 'inline';
      } else {
        this.style.display = 'none';
      }
      return state;
    },
    // UI 参数
    UI: {
      Click: null, // 单击事件
      Dblclick: null, // 双击事件
      Mousedown: null, // 鼠标按下
      Mouseup: null, // 释放事件
      Mouseout: null, // 移出事件(电脑端)
      Mousemove: null, // 移动事件
      Move: false, // 启动移动
      RelativeSize: false, // 相对父元素大小
    }
  };
  /****************************初始化扩展**************************/
  // 框架初始化
  PetUI.onload = new PetUI.SetOnload(window);
  // 注册全局事件
  // 对全局移动 PetUI.Mousemove 初始化
  PetUI.Mousemove = null;
  PetUI.__Mousemove = new PetUI.SetChangeEvent(PetUI, 'Mousemove');
  PetUI.AddHandler(document, "mousemove", PetUI.Mousemove);
  PetUI.AddHandler(document, "touchmove", PetUI.Mousemove, {
    passive: true
  });
  // 对全局移动 PetUI.Click 初始化
  PetUI.Click = null;
  PetUI.__Click = new PetUI.SetChangeEvent(PetUI, 'Click');
  PetUI.AddHandler(document, "click", PetUI.Click);
  PetUI.AddHandler(document, "touchstart", PetUI.Click, {
    passive: true
  });
  // 初始化窗口大小被改变与滚动条滚动事件
  PetUI.Position.AddResizeAffair = new PetUI.SetChangeEvent(PetUI.Position, 'ResizeAffair');
  PetUI.Position.AddResizeScroll = new PetUI.SetChangeEvent(PetUI.Position, 'ResizeScroll');
  /****************************UI****************************/
  // 初始化传递事件
  var obj = null,
    MouseDown = false,
    // 移动位置
    Page = {
      X: 0,
      Y: 0,
    };
  // 事件处理
  var $ = function (event) {
    // 获得event对象兼容性写法 
    event = event || (event = window.event);
    // 获得target兼容型写法 
    event.target = event.target || event.srcElement;
    // 移动端事件
    if (typeof touches != "undefined") {
      var touch = [];
      touch = (event.touches && event.changedTouches)[0];
      touch.buttons = 1;
      touch.event = event;
    }
    // 阻止浏览器默认行为兼容性写法 

    if (MouseDown) {
      if (event.preventDefault) {
        event.preventDefault();
      } else {
        event.returnValue = false;
      }
      // 阻止冒泡写法 
      if (event.stopPropagation) {
        event.stopPropagation();
      } else {
        event.cancelBubble = true;
      }
    }

    // 事件类型
    let T = null;
    switch (event.type) {
      case "click":
      case "touchstart":
        T = "Click";
        break;
      case "dblclick":
        T = "Dblclick";
        break;
      case "mouseup":
      case "touchend":
        T = "Mouseup";
        break;
      case "mouseout":
        T = "Mouseout";
        break;
      case "mousedown":
        T = "Mousedown";
        break;
      case "mousemove":
      case "touchmove":
        T = "Mousemove";
        break;
    }
    // 元素移动处理
    if (event.target.UI != undefined) {
      if (event.target.UI.Move) {
        obj = event.target; // 设置移动
        // 设置CSS
        obj.CSS({
          "position": "absolute"
        });
      }
    }
    // 判断是否移动
    if (obj != null) {
      switch (T) {
        case "Click": // 鼠标按下
          if (event.target != obj && MouseDown) {
            obj = null;
            MouseDown = false;
            Page.X = Page.Y = 0;
          }
          break;
        case "Mousedown": // 鼠标按下
          if (event.target != obj && MouseDown) {
            obj = null;
            MouseDown = false;
            Page.X = Page.Y = 0;
          } else {
            // 按下
            // 记录坐标
            Page.X = event.clientX - parseInt(obj.offsetLeft);
            Page.Y = event.clientY - parseInt(obj.offsetTop);
            // 启动移动
            MouseDown = true;
          }
          break;
        case "Mousemove":
          if (MouseDown) {
            let button = event.buttons;
            if (button == 1 || button == 3) {
              let X = (event.clientX - Page.X);
              let Y = (event.clientY - Page.Y);
              // 范围约束
              if (X < 1 || Y < 1 ||
                X + obj.offsetWidth > (PetUI.Position.Win.Width + PetUI.Position.Scroll.X) ||
                Y + obj.offsetHeight > (PetUI.Position.Win.Height + PetUI.Position.Scroll.Y)
              ) {
                return false;
              }
              // 修改位置
              obj.style.top = Y + 'px';
              obj.style.left = X + 'px';
            } else {
              obj = null;
              MouseDown = false;
              Page.X = Page.Y = 0;
            }
          }
          break;
      }
      return;
    }
    // 事件处理
    if (event.target.UI != undefined && typeof event.target.UI[T] == "function") {
      if (T != null) {
        if (event.target.UI[T] != undefined) {
          event.target.UI[T]({
            target: event.target, // 点击目标元素
            // 鼠标 / 键盘属性
            altKey: event.altKey, //	返回当事件被触发时，"ALT" 是否被按下。
            button: event.button, //返回当事件被触发时，哪个鼠标按钮被点击。
            clientX: event.clientX, //	返回当事件被触发时，鼠标指针的水平坐标。
            clientY: event.clientY, //	返回当事件被触发时，鼠标指针的垂直坐标。
            ctrlKey: event.ctrlKey, //	返回当事件被触发时，"CTRL" 键是否被按下。
            metaKey: event.metaKey, //返回当事件被触发时，"meta" 键是否被按下。
            relatedTarget: event.relatedTarget, //	返回与事件的目标节点相关的节点。
            screenX: event.screenX, //	返回当某个事件被触发时，鼠标指针的水平坐标。
            screenY: event.screenY, //	返回当某个事件被触发时，鼠标指针的垂直坐标。
            shiftKey: event.shiftKey, // 返回当事件被触发时，"SHIFT" 键是否被按下。
            // 位置
            offsetX: event.offsetX,
            offsetY: event.offsetY, //	发生事件的地点在事件源元素的坐标系统中的 x 坐标和 y 坐标。
            x: event.x,
            y: event.y //事件发生的位置的 x 坐标和 y 坐标，它们相对于用CSS动态定位的最内层包容元素。
          });
        }
      }
    } else {
      // 实现冒泡
      let obj = event.target.parentNode;
      for (; obj != undefined;) {
        if (obj.UI != undefined) {
          if (obj.UI[T] != undefined) {
            obj.UI[T]({
              target: event.target, // 点击目标元素
              // 鼠标 / 键盘属性
              altKey: event.altKey, //	返回当事件被触发时，"ALT" 是否被按下。
              button: event.button, //返回当事件被触发时，哪个鼠标按钮被点击。
              clientX: event.clientX, //	返回当事件被触发时，鼠标指针的水平坐标。
              clientY: event.clientY, //	返回当事件被触发时，鼠标指针的垂直坐标。
              ctrlKey: event.ctrlKey, //	返回当事件被触发时，"CTRL" 键是否被按下。
              metaKey: event.metaKey, //返回当事件被触发时，"meta" 键是否被按下。
              relatedTarget: event.relatedTarget, //	返回与事件的目标节点相关的节点。
              screenX: event.screenX, //	返回当某个事件被触发时，鼠标指针的水平坐标。
              screenY: event.screenY, //	返回当某个事件被触发时，鼠标指针的垂直坐标。
              shiftKey: event.shiftKey, // 返回当事件被触发时，"SHIFT" 键是否被按下。
              // 位置
              offsetX: event.offsetX,
              offsetY: event.offsetY, //	发生事件的地点在事件源元素的坐标系统中的 x 坐标和 y 坐标。
              x: event.x,
              y: event.y //事件发生的位置的 x 坐标和 y 坐标，它们相对于用CSS动态定位的最内层包容元素。
            });
          }
          return;
        } else {
          obj = obj.parentNode;
        }
      }
    }
  };
  // * 注册事件
  PetUI.RegisteredEvents = function (Obj) {
    PetUI.AddHandler(Obj, "click", $);
    PetUI.AddHandler(Obj, "dblclick", $);
    PetUI.AddHandler(Obj, "mouseup", $);
    PetUI.AddHandler(Obj, "mouseout", $);
    PetUI.AddHandler(Obj, "mousedown", $);
    PetUI.AddHandler(Obj, "mousemove", $);
    // 移动端事件注册
    PetUI.AddHandler(Obj, 'touchstart', $, false);
    PetUI.AddHandler(Obj, 'touchmove', $, false);
    PetUI.AddHandler(Obj, 'touchend', $, false);
  }
  PetUI.RegisteredEvents(document)
  /**************************附加功能*************************/
  // 加载样式
  PetUI.SetCSS = function (href) {
    var link = PetUI.Create('link');
    link.href = href;
    link.type = "text/css";
    link.rel = "stylesheet";
    document.head.appendChild(link);
    return link;
  };
  // 加载样式
  PetUI.SetStyle = function (href) {
    var link = PetUI.Create('style').Child();
    link.innerHTML = href;
    return link;
  };
  // 加载脚本
  PetUI.SetJS = function (src) {
    var script = PetUI.Create('script');
    script.src = src;
    document.head.appendChild(script);
    // 处理加载完成
    PetUI.SetJS.onload.lock = false;
    PetUI.SetJS.LoadingQuantity++;
    script.onload = script.onreadystatechange = function () {
      if (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") {
        PetUI.SetJS.onload.lock = true;
        PetUI.SetJS.LoadingQuantity--;
        if (PetUI.SetJS.LoadingQuantity == 0) {
          PetUI.SetJS.onload.onload();
        }
      }
    };
    return script;
  };
  // 加载初始化完成
  PetUI.SetJS.LoadingQuantity = 0;
  new PetUI.SetOnload(PetUI.SetJS);
  /**********************Analysis 解析器*********************/
  // Analysis 解析器
  function Analysis() {
    // Templates 模板数据
    this.Templates = "";
    // ParseTheList 解析列表
    this.ParseTheList = {};
    // Variate 解析变量
    this.Variate = {};
    // 模板的变量
    this.AnalyticalVariables = {
      css: "",
      js: {}
    };
    // 解析公用变量
    this.$ = {
      TheFirstParsing: 0,
      TabFirstParsing: true
    };
  }
  // 解析器继承
  Analysis.prototype = {
    // Analyze 分析
    Analyze: function () {
      // 处理-分词
      // 循环查找 单词|单词边界|空白/非空白字符|换行 
      // ([\S|\s|\w|\b|\n]{1,})
      // 查找 $ *{{ 标记开头
      // $([\S|\w|\n|\b]{1,})\{\{
      // 查找 {{*}} 内容
      // \{\{([\S|\w|\n|\b]{1,})\}\}
      // 可用 $* | {{*}}
      // \$[^\{\{|\s]{1,}|\{\{(.*?)\}\}
      // 处理-分词正则
      let split = this.Templates.split(this.Regular);
      //let match = Templates.match(this.Regular);
      //console.log(match);
      // 递归处理-层
      let n = 0;
      let analysis = function () {
        //-> 因为正则解析的原因 解析对象完全为 $*{{|{{*}}|}} 所以可用直接 '{{'[0] == '{' 来判断标记
        let ParseTheList = [];
        for (; n < split.length; n++) {
          let sp = split[n];
          if (sp[0] == "$") {
            n++;
            // 递归
            let arr = sp.split("-");
            let str = "";
            let strType = "";
            if (arr[1] != undefined) {
              str = arr[1].substr(0, arr[1].length - 2);
              strType = arr[0].substr(1);
            } else {
              strType = arr[0].substr(1, arr[0].length - 3);
            }
            ParseTheList.push({
              Type: strType,
              Variate: str, // 保存变量名由解析处理器来进行下一步处理
              Analysis: analysis()
            });
          } else if (sp[0] == "{") {
            let str = sp.substr(2, sp.length - 4);
            ParseTheList.push({
              Type: "this",
              Variate: str
            });
          } else if (sp[0] == "}") {
            return ParseTheList;
          } else if (sp.trim() == "") {} else {
            ParseTheList.push(sp);
          }
        }
        return ParseTheList;
      };
      this.ParseTheList = analysis();
    },
    // Update 更新值
    Update: function (div) {
      this.$.TheFirstParsing += 1;
      // 解析模板
      var _this = this;
      var dispose = function (ParseTheList, Variate) {
        let str = "";
        for (let key in ParseTheList) {
          let Obj = ParseTheList[key];
          if (typeof Obj == "string") {
            str += Obj;
          } else {
            // 处理自身变量
            if (Obj.Type == "this") {
              if (Variate != undefined && Variate[Obj.Variate] != undefined) {
                str += Variate[Obj.Variate];
              } else {
                if (div != undefined) {
                  console.warn("解析异常-变量不存在:", Obj.Variate, "\n", Obj);
                }
                return "";
              }
            }
            // 处理其他传递
            if (Obj.Analysis != undefined) {
              let obj = _this.AnalyticalProcess[Obj.Type];
              let configuration = _this.AnalyticalProcessConfiguration[Obj.Type];
              // 判断是否只进行一次
              if (configuration != undefined) {
                if (_this.$.TabFirstParsing != configuration.ParseOnlyOnce) {
                  continue; // 已经执行过一次跳过处理
                }
              } else {
                configuration = {};
              }
              // 处理变量
              if (obj != undefined) {
                let a = obj.call(_this, Obj.Analysis, configuration.ParameterName ? Obj.Variate : Variate[Obj.Variate]);
                if (a != undefined) {
                  str += a;
                }
              } else {
                // 默认处理
                if (PetUI.ToString(Variate[Obj.Variate]) == "Array") {
                  for (const key in Variate[Obj.Variate]) {
                    str += dispose(Obj.Analysis, Variate[Obj.Variate][key]);
                  }
                } else {
                  str += dispose(Obj.Analysis, Variate[Obj.Variate]);
                }
              }
            }
          }
        }
        return str;
      };
      // * 解析
      let rue = dispose(this.ParseTheList, this.Variate);
      // * 处理节点参数
      this.$.TheFirstParsing -= 1;
      if (this.$.TheFirstParsing == 0) {
        if (this.$.TabFirstParsing) {
          this.$.TabFirstParsing = false;
        }
        if (div != undefined) {
          // 注册模板事件
          div.innerHTML = rue;
          rue = this.UpdateNode(div, div);
        }
      }
      return rue;
    },
    // 处理节点
    UpdateNode: function (node, div) {
      node = node.children;
      for (let i = 0, len = node.length; i < len; i++) {
        node[i].$ = this.$;
        this.UpdateNode(node[i], div);
        // * 处理参数
        let event = node[i].attributes;
        for (let n = 0, lenN = event.length; n < lenN; n++) {
          let name = event[n].name;
          if (name.substr(0, 1) == "@") {
            name = name.substr(1);
            // 设置参数
            // * _this 解析得到Js对象
            // * Template 解析得到Js对象
            node[i][name] = new Function("_this", "Template", "return function (...Value){" + event[n].nodeValue + "}").call({}, this.AnalyticalVariables.js, div);
          }
        }
      }
    },
    // AnalyticalProcess 处理过程
    AnalyticalProcess: {
      "for": function (ParseTheList, Variate) {
        let Ay = new Analysis();
        let str = "";
        Ay.$ = this.$;
        // 继承模板
        Ay.ParseTheList = ParseTheList;
        // 处理
        if (PetUI.ToString(Variate) == "Array") {
          for (let i in Variate) {
            Ay.Variate = Variate[i];
            str += Ay.Update();
          }
        } else {
          Ay.Variate = Variate;
          str += Ay.Update();
        }
        return str;
      },
      "css": function (ParseTheList, Variate) {
        let str = "";
        for (let i in ParseTheList) {
          str += ParseTheList[i];
        }
        this.AnalyticalVariables.css += str;
      },
      "js": function (ParseTheList, Variate) {
        if (Variate == undefined) {
          console.log("Js 函数名不存在:", ParseTheList, "\n", Variate);
        } else {
          let str = "";
          for (let i in ParseTheList) {
            str += ParseTheList[i];
          }
          this.AnalyticalVariables.js[Variate] = new Function("return function (...Value){" + str + "}").call({});
        }
      },
      "if": function (ParseTheList, Variate) {
        // * 参数处理
        if (Variate != undefined) {
          // 继承解析
          let Ay = new Analysis();
          Ay.ParseTheList = ParseTheList;
          if (PetUI.ToString(Variate) == "Object") {
            Ay.Variate = Variate;
          } else {
            Ay.Variate = this.Variate;
          }
          return Ay.Update();
        }
        // * 直接处理 
        return "";
      },
      "@": function (ParseTheList, Variate) {
        // * 继承解析
        let Ay = new Analysis();
        Ay.ParseTheList = ParseTheList;
        if (PetUI.ToString(Variate) == "Object") {
          Ay.Variate = Variate;
        } else {
          Ay.Variate = this.Variate;
        }
        // * 执行函数
        return eval(Ay.Update());
      }
    },
    // AnalyticalProcessConfiguration 处理过程配置
    AnalyticalProcessConfiguration: {
      js: {
        ParameterName: true, // 不解析变量名对应的值
        ParseOnlyOnce: true // 只解析一次
      },
      css: {
        ParameterName: true,
        ParseOnlyOnce: true
      }
    },
    // Regular 分词正则
    Regular: /(\$[^\{\{|\s]{1,}\{\{|\{\{.*?\}\}|\}\})/ig
  };
  // 设置特殊函数
  PetUI.Analysis = Analysis;
  /**************************完成创建*************************/
  this.petui = this.PetUI = PetUI;
})();